import cryptoFramework from "@ohos.security.cryptoFramework"
import { DataBlob, SymKey, KeyPair } from './types'

export enum SymAlg {
  NONE = 0,
  DES = 1,
  AES = 2,
  SM4 = 4,
  HMAC = 5,
}

export class SymKenGen {
  private keygen: cryptoFramework.SymKeyGenerator;

  constructor(alg: SymAlg) {
    this.keygen = this.createKeyGen(alg);
  }

  generateKey(): Promise<SymKey> {
    return new Promise((resolve, reject) => {
      this.keygen.generateSymKey()
        .then(symkey => {
          resolve(symkey);
        })
        .catch(err => {
          reject(err);
        });
    });
  }

  convertKey(key: Uint8Array): Promise<SymKey> {
    return new Promise((resolve, reject) => {
      this.keygen.convertKey(new DataBlob(key))
        .then(symkey => {
          resolve(symkey);
        })
        .catch(err => {
          reject(err);
        });
    });
  }

  getAlgName(alg: SymAlg): string {
    let algName: string = null;
    switch (alg) {
      case SymAlg.DES:
        algName = 'DES';
        break;
      case SymAlg.AES:
        algName = 'AES';
        break;
      case SymAlg.HMAC:
        algName = 'HMAC';
        break;
      case SymAlg.SM4:
        algName = 'SM4';
        break;
    }

    return algName;
  }

  private createKeyGen(alg: SymAlg): cryptoFramework.SymKeyGenerator {
    try {
      return cryptoFramework.createSymKeyGenerator(this.getAlgName(alg));
    } catch (error) {
      console.error("[createKeyGen]: error code: " + error.code + ", message is: " + error.message);
      return null;
    }
  }
}

export enum AsymAlg {
  NONE = 0,
  RSA = 1,
  SM2 = 2,
  ECC = 3,
  DSA = 4,
  ED25519 = 5,
  DH = 6,
}

export class AsymKenGen {
  private keygen: cryptoFramework.AsyKeyGenerator;

  constructor(alg: AsymAlg) {
    this.keygen = this.createKeyGen(alg);
  }

  generateKeyPair(): Promise<KeyPair> {
    return new Promise((resolve, reject) => {
      this.keygen.generateKeyPair()
        .then(keyPair => {
          resolve(keyPair);
        })
        .catch(err => {
          reject(err);
        });
    });
  }

  convertKey(pubKey: DataBlob, priKey: DataBlob): Promise<KeyPair> {
    return new Promise((resolve, reject) => {
      this.keygen.convertKey(pubKey, priKey)
        .then(keyPair => {
          resolve(keyPair);
        })
        .catch(err => {
          reject(err);
        });
    });
  }

  getAlgName(alg: AsymAlg): string {
    let algName: string = null;
    switch (alg) {
      case AsymAlg.RSA:
        algName = 'RSA';
        break;
      case AsymAlg.SM2:
        algName = 'SM2';
        break;
      case AsymAlg.ECC:
        algName = 'ECC';
        break;
      case AsymAlg.DSA:
        algName = 'DSA';
        break;
      case AsymAlg.ED25519:
        algName = 'ED25519';
        break;
      case AsymAlg.DH:
        algName = 'DH';
        break;
    }

    return algName;
  }

  private createKeyGen(alg: AsymAlg): cryptoFramework.AsyKeyGenerator {
    try {
      return cryptoFramework.createAsyKeyGenerator(this.getAlgName(alg));
    } catch (error) {
      console.error("[createKeyGen]: error code: " + error.code + ", message is: " + error.message);
      return null;
    }
  }
}